


#include <gfx/light.h>
#include <gfx/iprogramparameter.h>


ceLight::ceLight ()
	: _position (0, 0, 0, 1)
	,	_range (0.0f)
	, _attenuation (1.0f, 0.0f, 0.0f)
	, _rangeMode (LRM_Const)
	, _ambient (0.0f, 0.0f, 0.0f, 1.0f)
	, _diffuse (1.0f, 1.0f, 1.0f, 1.0f)
	, _specular (1.0f, 1.0f, 1.0f, 1.0f)
	, _lightType (LT_Point)
{

}

void ceLight::SetPosition(const ceVector3f &position)
{
	_position = ceVector4f (position.x, position.y, position.z, 1.0f);
	_lightType = LT_Point;
}

const ceVector3f& ceLight::GetPosition() const
{
	return _position.AsVector3();
}

void ceLight::SetDirection(const ceVector3f &direction)
{
	_position = ceVector4f (direction.x, direction.y, direction.z, 0.0f);
	_lightType = LT_Directional;
}

const ceVector3f& ceLight::GetDirection () const
{
	return _position.AsVector3();
}


ceLightType ceLight::GetLightType() const
{
	return _lightType;
}

void ceLight::SetRange(float range)
{
	_range = range;
	if (_range < 0.001f)
		{
			_attenuation = ceVector3f (1.0f, 0.0f, 0.0f);
			return;
		}

	switch (_rangeMode)
		{
		case LRM_Const:
			_attenuation = ceVector3f (1.0f, 0.0f, 0.0f);
			break;

		case LRM_Linear:
			_attenuation = ceVector3f (1.0f, -1.0f / _range, 0.0f);
			break;

		case LRM_Quadratic:
			_attenuation = ceVector3f (1.0f, 0.0f, -1.0f / (_range * _range));
			break;
		}

}



float ceLight::GetRange() const
{
	return _range;
}

void ceLight::SetRangeMode(ceLightRangeMode mode)
{
	_rangeMode = mode;

	// reset set the range to update the attenuation factors
	SetRange(_range);
}


ceLightRangeMode ceLight::GetRangeMode() const
{
	return _rangeMode;
}


void ceLight::SetAmbient(const ceColor4f &ambient)
{
	_ambient = ambient;
}

const ceColor4f& ceLight::GetAmbient () const
{
	return _ambient;
}

void ceLight::SetDiffuse(const ceColor4f &diffuse)
{
	_diffuse = diffuse;
}

const ceColor4f& ceLight::GetDiffuse () const
{
	return _diffuse;
}

void ceLight::SetSpecular(const ceColor4f &specular)
{
	_specular = specular;
}

const ceColor4f& ceLight::GetSpecular () const
{
	return _specular;
}


void ceLight::Bind(iProgram *program)
{
	iProgramParameter *pp = 0;

	pp = program->GetParameter(PPB_LightAmbient);
	if (pp) pp->Bind(_ambient);

	pp = program->GetParameter(PPB_LightDiffuse);
	if (pp) pp->Bind(_diffuse);

	pp = program->GetParameter(PPB_LightSpecular);
	if (pp) pp->Bind(_specular);

	pp = program->GetParameter(PPB_LightPosition);
	if (pp) pp->Bind(_position);

	pp = program->GetParameter(PPB_LightAttenuation);
	if (pp) pp->Bind(_attenuation);
}
